"""
房天下项目数据接口
"""
import datetime

import jwt
from django.core.cache import caches
from django.db.transaction import atomic
from django.utils import timezone
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.decorators import api_view, action
from rest_framework.filters import OrderingFilter
from rest_framework.generics import ListAPIView, RetrieveAPIView
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from rest_framework_extensions.cache.mixins import CacheResponseMixin

from api.auths import CustomAuthentication, CustomPermission, AllowGetAuthentication, AllowPostAuthentication
from api.auxs import CustomThrottle, CustomPagination
from api.consts import TEL_PATTERN
from api.filters import AgentFilterSet, HouseInfoFilterSet
from api.serializers import DistrictSimpleSerializer, DistrictDetailSerializer, HouseTypeSerializer, \
    AgentDetailSerializer, HouseInfoSimpleSerializer, EstateDetailSerializer, HouseInfoDetailSerializer, \
    EstateSerializer, TagSerializer, HouseInfoSerializer, UserCreateSerializer, \
    UserUpdateSerializer, HousePhotoSerializer, UserSimpleSerializer
from common.utils import gen_mobile_code, send_sms_by_luosimao, to_md5_hex, get_ip_address
from common.models import District, HouseType, Agent, HouseInfo, Estate, Tag, User, LoginLog, HousePhoto
from fangtx.settings import SECRET_KEY


@api_view(('POST', ))
def login(request):
    """登录（获取用户身份令牌）"""
    username = request.data.get('username')
    password = request.data.get('password')
    if username and password:
        password = to_md5_hex(password)
        user = User.objects.filter(username=username, password=password).first()
        if user:
            # 用户登录成功通过JWT生成用户身份令牌
            payload = {
                'exp': datetime.datetime.utcnow() + datetime.timedelta(days=1),
                'data': {'userid': user.userid, }
            }
            token = jwt.encode(payload, SECRET_KEY, algorithm='HS256').decode()
            with atomic():
                current_time = timezone.now()
                if not user.lastvisit or \
                        (current_time - user.lastvisit).days >= 1:
                    user.point += 2
                    user.lastvisit = current_time
                    user.save()
                loginlog = LoginLog()
                loginlog.user = user
                loginlog.logdate = current_time
                loginlog.ipaddr = get_ip_address(request)
                loginlog.save()
            data = {'code': 20001, 'token': token}
        else:
            data = {'code': 20002, 'hint': '用户名或密码错误'}
    else:
        data = {'code': 20003, 'hint': '请输入有效的登录信息'}
    return Response(data)


@api_view(('GET', ))
def send_code_by_sms(request, tel):
    """发送短信验证码（异步化）"""
    if TEL_PATTERN.fullmatch(tel):
        if caches['default'].get(tel):
            data = {'code': 10002, 'msg': '请不要在120秒以内重复发送手机验证码'}
        else:
            code = gen_mobile_code()
            message = f'您的短信验证码是{code}，打死也不能告诉别人哟！【Python小课】'
            # 被@app.task装饰的函数可以通过delay异步调用
            # 异步执行的函数相当于是消息的生产者，会向消息队列放一个消息
            # 如果想消费掉这个消息还需要启动消息的消费者
            # celery -A fangtx worker -l debug &
            send_sms_by_luosimao.delay(tel, message=message)
            caches['default'].set(tel, code, timeout=120)
            data = {'code': 10001, 'msg': '短信验证码发送成功'}
    else:
        data = {'code': 10003, 'msg': '请提供有效的手机号'}
    return Response(data)


# @throttle_classes((AnonRateThrottle, ))
# @cache_page(timeout=86400 * 365, cache='default', key_prefix='provs')
# @api_view(('GET', ))
# def get_provinces(request):
#     queryset = District.objects.filter(parent__isnull=True).only('distid', 'name')
#     serializer = DistrictSimpleSerializer(queryset, many=True)
#     return Response(serializer.data)


# 声明式缓存
@method_decorator(cache_page(timeout=86400 * 365, cache='default', key_prefix='provs'), name='get')
class ProvinceView(ListAPIView):
    """省级行政区域视图"""
    queryset = District.objects.filter(parent__isnull=True).only('distid', 'name')
    serializer_class = DistrictSimpleSerializer
    pagination_class = None


class DistrictView(RetrieveAPIView):
    """行政区域详情视图"""
    queryset = District.objects.all()
    serializer_class = DistrictDetailSerializer
    pagination_class = None


class HotCityView(ListAPIView):
    """热门城市视图"""
    queryset = District.objects.filter(ishot=True).only('distid', 'name')
    serializer_class = DistrictSimpleSerializer
    pagination_class = None


class HouseTypeViewSet(CacheResponseMixin, ModelViewSet):
    """房源户型视图集"""
    queryset = HouseType.objects.all()
    serializer_class = HouseTypeSerializer
    pagination_class = None
    authentication_classes = (AllowGetAuthentication, CustomAuthentication)
    permission_classes = (CustomPermission, )


@method_decorator(
    decorator=cache_page(cache='default', timeout=300, key_prefix='agents'),
    name='list'
)
class AgentViewSet(ModelViewSet):
    """经理人视图集"""
    queryset = Agent.objects.all()
    serializer_class = AgentDetailSerializer
    filter_backends = (DjangoFilterBackend, OrderingFilter)
    filterset_class = AgentFilterSet
    ordering = ('-servstar', 'agentid')
    ordering_fields = ('servstar', 'realstar')
    throttle_classes = (CustomThrottle, )
    pagination_class = CustomPagination


class EstateViewSet(ModelViewSet):
    """楼盘视图集"""
    queryset = Estate.objects.all()\
        .select_related('district').order_by('estateid')
    serializer_class = EstateDetailSerializer
    filter_backends = (DjangoFilterBackend, OrderingFilter)
    filterset_fields = ('district', )
    ordering = ('-hot', )
    authentication_classes = (CustomAuthentication, )
    permission_classes = (CustomPermission, )

    def get_serializer_class(self):
        if self.action in ('create', 'update'):
            return EstateSerializer
        return self.serializer_class


class TagViewSet(ModelViewSet):
    """房源标签视图集"""
    queryset = Tag.objects.all()
    serializer_class = TagSerializer


class HouseInfoViewSet(ModelViewSet):
    """房源视图集"""
    queryset = HouseInfo.objects.all()
    serializer_class = HouseInfoDetailSerializer
    filter_backends = (DjangoFilterBackend, OrderingFilter)
    # 根据filter_fields指定的属性可以做精确查询
    # filter_fields = ('price', 'area')
    filterset_class = HouseInfoFilterSet
    ordering = ('-pubdate', )
    ordering_fields = ('pubdate', 'price')

    @action(methods=('GET', ), detail=True)
    def photos(self, request, pk):
        queryset = HousePhoto.objects.filter(house=self.get_object())
        return Response(HousePhotoSerializer(queryset, many=True).data)

    def get_queryset(self):
        if self.action == 'list':
            return self.queryset\
                .only('houseid', 'title', 'area', 'floor', 'totalfloor', 'price',
                      'mainphoto', 'priceunit', 'street', 'district_level3', 'type')\
                .select_related('district_level3', 'type')\
                .prefetch_related('tags')
        return self.queryset\
            .defer('user', 'district_level2')\
            .select_related('district_level3', 'type', 'estate', 'agent')\
            .prefetch_related('tags')

    def get_serializer_class(self):
        if self.action == 'list':
            return HouseInfoSimpleSerializer
        elif self.action in ('create', 'update'):
            return HouseInfoSerializer
        return self.serializer_class


@method_decorator(decorator=atomic(), name='create')
class UserViewSet(ModelViewSet):
    """用户视图集"""
    queryset = User.objects.all()
    serializer_class = UserSimpleSerializer
    authentication_classes = (AllowPostAuthentication, CustomAuthentication)
    permission_classes = (CustomPermission, )

    def get_serializer_class(self):
        if self.action == 'create':
            return UserCreateSerializer
        elif self.action == 'update':
            return UserUpdateSerializer
        return self.serializer_class
